using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEditor;
using System.IO;
using System.Linq;
using System.Text;
using System.Xml.Schema;
using Localize;

// using UnityEditor.WindowsStandalone;

namespace CIV
{
    /// <summary>
    /// i18n是“国际化”的简称,通常与i18n相关的还有L10n（“本地化”的简称）
    /// </summary>
    public class ExtractLocalizeTxt
    {
        private Dictionary<string, string> langs;
        public ExtractLocalizeTxt()
        {
            langs = loadLangData();
        }

        private string LastPath
        {
            get
            {
                string sss = EditorPrefs.GetString(Application.productName + "_Local", "");
                if (string.IsNullOrEmpty(sss))
                {
                    sss = Application.dataPath;
                }
                return sss;
            }
            set { EditorPrefs.SetString(Application.productName + "_Local", value); }
        }

        public int Extract(string fileData, string fileName, List<string> container)
        {
            List<string> newKsys = new List<string>();
            //i18n._("frind_list","好友列表  {0}/{1}")
            //MatchCollection matches = Regex.Matches(file, "i18n\\._\\(\\\"(.+?)\\\"", RegexOptions.IgnorePatternWhitespace);
            MatchCollection matches = Regex.Matches(fileData, "i18n\\._\\((\\\"(.+?)\\\")\\)",
                RegexOptions.IgnorePatternWhitespace);
            foreach (Match match in matches)
            {
                string key = match.Groups[1].Value;
                string value = null;
                string world = null;
                MatchCollection values = Regex.Matches(key, "(\\\"(.+?)\\\")", RegexOptions.IgnorePatternWhitespace);

                if (values.Count < 1)
                    continue;
                // bool isKey = false;
                key = values[0].Groups[2].Value;

                if (values.Count > 1)
                {
                    value = values[1].Groups[2].Value;
                    world = i18n.RN2NewLine(value);
                    if (langs.ContainsValue(world))
                    {
                        foreach (KeyValuePair<string, string> kv in langs)
                        {
                            if (kv.Value.Equals(world))
                            {
                                if (!kv.Key.Equals(key))
                                    container.Add(fileName + " > 请将\"" + key + "=" + value + "\"的key替换为\"" + kv.Key + "\"");
                                break;
                            }
                        }
                        continue;
                    }
                }

                if (langs.ContainsKey(key))
                {
                    if (value != null)
                    {
                        if (world != langs[key])
                            container.Add(fileName + " > key冲突: " + key + "=" + value);
                    }
                    continue;
                }
                else
                    container.Add(key + "=" + (value == null ? "\"null\"" : value));

                newKsys.Add(string.Format("public const string  {0}=\"{1}\";", key, key));
                this.langs.Add(key, world);
            }

            container.Add("\n\n");
            foreach (var v in newKsys)
            {
                container.Add(v);
            }
            return newKsys.Count;
        }

        public List<string> CheckLocalized(string filePath, string fileData, string fileName)
        {
            List<string> result = new List<string>();
            MatchCollection matches = Regex.Matches(fileData, "i18n\\._\\((\\\"(.+?)\\\")\\)", RegexOptions.IgnorePatternWhitespace);
            foreach (Match match in matches)
            {
                string key = match.Groups[1].Value;
                MatchCollection values = Regex.Matches(key, "(\\\"(.+?)\\\")", RegexOptions.IgnorePatternWhitespace);

                if (values.Count < 1) continue;
                key = values[0].Groups[2].Value;
                if (langs.ContainsKey(key)) continue;
                result.Add(filePath + "=" + key);
            }
            return result;
        }

        [MenuItem("Tools/提取多语言 ", false, 17)]
        static private void Extract()
        {
            // string localPath = "";

            ExtractLocalizeTxt extractor = new ExtractLocalizeTxt();
            List<string> txt = new List<string>();
            //script
            string path = EditorUtility.OpenFilePanelWithFilters("选择脚本文件", extractor.LastPath, new string[] { "*.cs", "cs" });
            if (string.IsNullOrEmpty(path))
                return;
            if (!File.Exists(path))
                return;
            Debug.Log("开始提取多语言=================");
            FileInfo f = new FileInfo(path);
            int newCount = extractor.Extract(File.ReadAllText(f.FullName), f.Name, txt);

            //save  
            FileInfo fi = new FileInfo(Application.dataPath + "/Test/ALL.rb");
            if (!fi.Directory.Exists)
                Directory.CreateDirectory(fi.Directory.FullName);
            using (FileStream fs = File.Open(fi.FullName, FileMode.OpenOrCreate))
            {
            }

            File.WriteAllLines(fi.FullName, txt.ToArray(), Encoding.UTF8);
            Debug.Log("多语言提取完毕=================Key count = " + newCount + "\n" + fi.FullName);
            extractor.LastPath = f.Directory.FullName;
            AssetDatabase.Refresh();
        }

        [MenuItem("Tools/提取多语言(目录) ", false, 18)]
        static private void ExtractFolder()
        {
            ExtractLocalizeTxt extractor = new ExtractLocalizeTxt();
            //script
            string path = EditorUtility.OpenFolderPanel("选择目录", extractor.LastPath, "");
            List<string> txt = new List<string>();
            int newCount = 0;
            Debug.Log("开始提取多语言=================");
            extractFolderByPath(extractor, path, newCount, txt);
            //save  
            FileInfo fiout = new FileInfo(Application.dataPath + "/Test/ALL.rb");
            if (!fiout.Directory.Exists)
                Directory.CreateDirectory(fiout.Directory.FullName);
            using (FileStream fs = File.Open(fiout.FullName, FileMode.OpenOrCreate))
            {
            }
            File.WriteAllLines(fiout.FullName, txt.ToArray(), Encoding.UTF8);
            Debug.Log("多语言提取完毕=================Key count = " + newCount + "\n" + fiout.FullName);
            AssetDatabase.Refresh();
        }

        static private void extractFolderByPath(ExtractLocalizeTxt extractor, string path, int newCount, List<string> txt)
        {
            if (string.IsNullOrEmpty(path))
                return;
            if (!Directory.Exists(path))
                return;
            string[] fils = Directory.GetFiles(path);
            foreach (var f in fils)
            {
                if (Path.GetExtension(f) != ".cs") continue;
                FileInfo fi = new FileInfo(f);
                newCount += extractor.Extract(File.ReadAllText(f), fi.Name, txt);
            }

            string[] folders = Directory.GetDirectories(path);
            foreach (var f in folders)
            {
                extractFolderByPath(extractor, f, newCount, txt);
            }
        }

        [MenuItem("Tools/检查本地化是否有遗漏", false, 19)]
        private static void CheckLocalized()
        {
            ExtractLocalizeTxt extractor = new ExtractLocalizeTxt();
            string path = EditorUtility.OpenFolderPanel("选择目录", extractor.LastPath, "");
            CheckLocalizedSync();
            CheckLocalizedByPath(extractor, path);
        }

        private static void CheckLocalizedSync()
        {
            Dictionary<string, Dictionary<string, string>> properties = new Dictionary<string, Dictionary<string, string>>();
            string[] allLanguageNames = Localize.i18n.AllLanguageNames;
            for (int i = 0; i < allLanguageNames.Length; i++)
            {
                if (allLanguageNames[i] == Localize.ELanguage.None.ToString()) continue;
                properties.Add(allLanguageNames[i], new Dictionary<string, string>());
                string path = R.RawResourcesRoot + "Localized/" + allLanguageNames[i] + "/";
                string[] files = System.IO.Directory.GetFiles(path, "*.txt");
                foreach (string file in files)
                {
                    string[] lines = System.IO.File.ReadAllLines(file);
                    foreach (string line in lines)
                    {
                        string[] kv = line.Split('=');
                        if (kv == null || kv.Length < 2)
                            continue;
                        string key = kv[0];
                        string value = "";
                        if (kv.Length > 2)
                        {
                            value = i18n.RN2NewLine(line.Substring(line.IndexOf("=") + 1));
                        }
                        else
                        {
                            value = i18n.RN2NewLine(kv[1]);
                        }
                        if (properties[allLanguageNames[i]].ContainsKey(key))
                        {
                            Debug.LogError("本地化有冲突 key=" + key);
                            continue;
                        }
                        properties[allLanguageNames[i]].Add(key, value);
                    }
                }
            }
            // 以CN为准，检查多语言key丢失
            Dictionary<string, Dictionary<string, string>> missingKeys = new Dictionary<string, Dictionary<string, string>>();
            foreach (KeyValuePair<string, Dictionary<string, string>> otherPair in properties)
            {
                if (otherPair.Key == Localize.ELanguage.CN.ToString()) continue;
                foreach (KeyValuePair<string, string> pair in properties[Localize.ELanguage.CN.ToString()])
                {
                    if (otherPair.Value.ContainsKey(pair.Key)) continue;
                    if (!missingKeys.ContainsKey(otherPair.Key)) missingKeys.Add(otherPair.Key, new Dictionary<string, string>());
                    missingKeys[otherPair.Key].Add(pair.Key, pair.Value);
                }
                if (missingKeys.ContainsKey(otherPair.Key))
                {
                    Debug.LogError("===============>" + otherPair.Key + " have misiing keys = " + missingKeys[otherPair.Key].Count);
                    FileInfo fiout = new FileInfo(Application.dataPath + "/Test/Missing_" + otherPair.Key + ".txt");
                    if (!fiout.Directory.Exists)
                        Directory.CreateDirectory(fiout.Directory.FullName);
                    string[] allLines = new string[missingKeys[otherPair.Key].Keys.Count];
                    int i = 0;
                    foreach (KeyValuePair<string, string> pair in missingKeys[otherPair.Key])
                    {
                        allLines[i] = pair.Key + "=" + pair.Value.Replace("\r", "\\r").Replace("\n", "");
                        i++;
                    }
                    File.WriteAllLines(fiout.FullName, allLines, Encoding.UTF8);
                }
            }
        }

        private static void CheckLocalizedByPath(ExtractLocalizeTxt extractor, string path)
        {
            List<string> allScripts = new List<string>();
            GetAllScripts(path, allScripts);
            int index = 0;
            List<string> results = new List<string>();
            if (allScripts.Count > 0)
            {
                EditorApplication.update = delegate ()
                {
                    bool isCancel = EditorUtility.DisplayCancelableProgressBar(Path.GetFileName(allScripts[index]), allScripts[index], (float)index / (float)allScripts.Count);
                    if (Path.GetExtension(allScripts[index]) == ".cs")
                    {
                        FileInfo fi = new FileInfo(allScripts[index]);
                        results.AddRange(extractor.CheckLocalized(allScripts[index], File.ReadAllText(allScripts[index]), fi.Name));
                    }
                    index++;

                    if (isCancel || index >= allScripts.Count)
                    {
                        EditorUtility.ClearProgressBar();
                        EditorApplication.update = null;

                        List<string> txt = new List<string>();
                        List<string> newKeys = new List<string>();
                        for (int i = 0; i < results.Count; i++)
                        {
                            string[] split = results[i].Split('=');
                            if (!newKeys.Contains(split[1]))
                                newKeys.Add(split[1]);
                            FileInfo f = new FileInfo(split[0]);
                            extractor.Extract(File.ReadAllText(f.FullName), f.Name, txt);
                        }
                        List<string> newLocalizedList = new List<string>();
                        for (int k = 0; k < newKeys.Count; k++)
                        {
                            for (int m = 0; m < txt.Count; m++)
                            {
                                if (txt[m].Contains(newKeys[k]))
                                {
                                    newLocalizedList.Add(txt[m]);
                                    break;
                                }
                            }
                        }
                        if (newLocalizedList.Count > 0)
                        {
                            //save  
                            FileInfo fiout = new FileInfo(Application.dataPath + "/Test/ALL.rb");
                            if (!fiout.Directory.Exists)
                                Directory.CreateDirectory(fiout.Directory.FullName);
                            using (FileStream fs = File.Open(fiout.FullName, FileMode.OpenOrCreate))
                            {
                            }
                            File.WriteAllLines(fiout.FullName, newLocalizedList.ToArray(), Encoding.UTF8);
                        }
                        Debug.LogError("=======>新增本地化行：" + newLocalizedList.Count);
                    }
                };
            }
        }

        private static void GetAllScripts(string path, List<string> all)
        {
            string[] files = Directory.GetFiles(path);
            for (int i = 0; i < files.Length; i++)
            {
                if (Path.GetExtension(files[i]) != ".cs") continue;
                all.Add(files[i]);
            }

            string[] folders = Directory.GetDirectories(path);
            for (int i = 0; i < folders.Length; i++)
            {
                GetAllScripts(folders[i], all);
            }
        }

        // private functions
        private static Dictionary<string, string> loadLangData()
        {
            Dictionary<string, string> dicLangs = new Dictionary<string, string>();
            string path = R.RawResourcesRoot + "Localized/" + ELanguage.CN.ToString() + "/";
            string[] files = System.IO.Directory.GetFiles(path, "*.txt");
            foreach (string file in files)
            {
                string[] lines = System.IO.File.ReadAllLines(file);
                Dictionary<string, string> dic = new Dictionary<string, string>();
                foreach (string line in lines)
                {
                    string[] kv = line.Split('=');
                    if (kv == null || kv.Length < 2) continue;
                    string key = kv[0];
                    string value = kv[1];
                    string word = i18n.RN2NewLine(value);
                    if (dicLangs.ContainsKey(key))
                    {
                        if (dicLangs[key] == word)
                            Debug.LogError(file + ">全局完全重复:" + key + "=" + value);
                        else
                            Debug.LogError(file + ">全局冲突key:" + key + "=" + value);
                    }
                    else
                    {
                        dicLangs.Add(key, word);
                    }
                }
            }
            return dicLangs;
        }
    }
}